package algorithms;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;

import stack.Stack;
import stack.StackIterator;
import templates.Operator;
import templates.State;

public abstract class Algorithm<Template> {
	protected Stack<State<Template>> btStack ;
	protected ArrayList<Operator<Template>> operators;
	protected State<Template> initialState;
	protected ArrayList<State<Template>> finalStates;
	protected int operatorNumber =0;
	protected PrintWriter logWriter = null;
	protected File log;
	
	protected boolean found(State<Template> thisState)
	{
		for(StackIterator<State<Template>> it=new StackIterator<State<Template>>(btStack); it.hasNext();)
		{
			if(thisState.equals(it.next())) return true;
		}
		return false;
	}
	
	
	public Algorithm(State<Template> iState,ArrayList<State<Template>> fStates,ArrayList<Operator<Template>> opr,String log)
	{
		btStack=new Stack<State<Template>>(100);
		initialState=iState;
		finalStates=fStates;
		operators=opr;
		operatorNumber=operators.size()-1;
		try {
			logWriter = new PrintWriter(new FileWriter(log));
		} catch (IOException e) {
			e.printStackTrace();
		}
		this.log=new File(log);
	}
	
	
	protected boolean solutionFound(State<Template> thisState)
	{
		for(int i=0; i<finalStates.size();i++)
			if (thisState.equals(finalStates.get(i)))
		return true;
		
		return false;
	}
	
	protected int getIndex(Operator<Template> operator)
	{
		for(int i=0;i<operators.size();i++)
		{

			if (operators.get(i).getOperatorNumber()==operator.getOperatorNumber()) return i;
		}
		return 0;

	}
	
	protected void print(State<Template> thisState)
	{
		logWriter.append("\n~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
		logWriter.append(thisState.getCurrentOperator().toString());
		logWriter.append('\n');
		logWriter.append(thisState.getCurrentState().toString());
		logWriter.append('\n');
	}
	
	protected void closeLog()
	{
		System.out.println("Solution found using Search... Stacktrace can be found in: " + log.getAbsolutePath());
		logWriter.close();
	}
	
	public void executeAlgorithm()
	{
		init();
		btStack.push(initialState);
		if(solveProblem()==true){
		for(StackIterator<State<Template>> it=new StackIterator<State<Template>>(btStack); it.hasNext();)
		{
			print(it.next());
		}
		closeLog();
		}
		else {logWriter.append("Error");
		logWriter.close();
		System.out.println("No Solution found using Search... Stacktrace can be found in: " + log.getAbsolutePath());
		}
	
	}
	public abstract boolean solveProblem();
	public abstract void init();
}
